package view;

import entity.ChessUser;
import message.*;
import message.BackResultMessage;
import model.ChessBoard;
import model.RoomInfo;
import socket.ChessClient;
import thread.AudioPlayerThread;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

/**
 * 在线房间页面设计
 *
 * @author 任禹名 张天羿 张紘溢
 */
public class OnlineRoom extends JFrame {
    public boolean gameStart;
    public static boolean isLeft;
    private RoomList roomList;
    private ChessUser chessUser;
    private ChessBoard chessBoard;
    private int rid;
    private boolean canBackGame;
    private boolean canPlay;
    private boolean canPlayBeforeRegret = false;
    private boolean readyPanelVisible = false;

    private JPanel roomBackground;
    private JPanel ButtonPanel = new JPanel();
    private JPanel anotherGamerPanel = new JPanel();
    private JPanel myGamerPanel = new JPanel();

    private JButton readyButton = new JButton("准备");
    private JButton exitButton = new JButton("退出本局");
    private JButton regretButton = new JButton("悔棋");
    private JButton giveInButton = new JButton("认输");

    JLabel myReadyLabel = new JLabel();
    JLabel myIconLabel = new JLabel();
    JLabel myNameLabel;
    JLabel anotherReadyLabel = new JLabel();
    JLabel anotherIconLabel = new JLabel();
    JLabel anotherNameLabel = new JLabel();

    public boolean isCanPlay() {
        return canPlay;
    }

    public static boolean isLeft() {
        return isLeft;
    }

    public void setCanPlay(boolean canPlay) {
        this.canPlay = canPlay;
    }

    public int getRid() {
        return rid;
    }

    public ChessBoard getChessBoard() {
        return chessBoard;
    }

    /**
     * 构造函数.
     *
     * @param roomid    RoomInfo里的房间编号
     * @param isLeft    判断是否是房间的左侧(黑棋)
     * @param roomList  上一个房间列表界面,方便退出
     * @param chessUser 进入房间的玩家
     * @see RoomInfo
     */
    public OnlineRoom(int roomid, boolean isLeft, RoomList roomList, ChessUser chessUser) {
        chessBoard = new ChessBoard(this, true);
        this.chessUser = chessUser;
        this.roomList = roomList;
        ChessClient.getInstance().setRoom(this);
        System.out.println("网络对战");
        this.rid = roomid;
        this.isLeft = isLeft;

        //有初始化顺序!需要使玩家信息值于最上层
        initMyPlayerPanel();
        initAnotherPlayerPanel();
        initRoomFrame();

        addAction();
        this.setVisible(true);

    }

    /**
     * 初始化主页面.
     */
    private void initRoomFrame() {
        this.setTitle("五子棋");
        this.setSize(1000, 800);
        this.setLocation((GameFrame.screenWidth - 1000) / 2, (GameFrame.screenHeight - 800) / 2);
        this.setResizable(false);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.getContentPane().setLayout(null);

        roomBackground = new JPanel() {
            protected void paintComponent(Graphics g) {
                Image image = new ImageIcon("resource/img/room.png").getImage();
                g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
            }
        };
        roomBackground.setBounds(0, 0, 1000, 800);
        roomBackground.setLayout(null);
        roomBackground.setOpaque(false);
        chessBoard.setBounds(215, 100, 545, 545);
        roomBackground.add(chessBoard);
        this.getContentPane().add(roomBackground);

        initButtonPanel();
    }

    /**
     * 初始化按钮界面.
     */
    private void initButtonPanel() {
        ButtonPanel.setBounds(173, 670, 515, 33);
        roomBackground.add(ButtonPanel);
        ButtonPanel.setLayout(null);
        ButtonPanel.setOpaque(false);

        readyButton.setBounds(150, 5, 80, 23);
        exitButton.setBounds(416, 5, 73, 23);
        regretButton.setBounds(240, 5, 78, 23);
        giveInButton.setBounds(328, 5, 78, 23);

        ButtonPanel.add(readyButton);
        ButtonPanel.add(exitButton);
        ButtonPanel.add(regretButton);
        ButtonPanel.add(giveInButton);
    }

    /**
     * 初始化自己的信息界面(左下角)
     */
    private void initMyPlayerPanel() {
        //本身设置
        myGamerPanel.setBounds(10, 408, 180, 290);
        myGamerPanel.setLayout(null);
        myGamerPanel.setOpaque(false);

        //玩家名设置
        myNameLabel = new JLabel(chessUser.getName());
        myNameLabel.setBounds(85, 110, 130, 45);
        myGamerPanel.add(myNameLabel);

        //玩家头像设置
        myIconLabel.setIcon(new ImageIcon(chessUser.getFileName()));
        myIconLabel.setBounds(62, 35, 70, 70);
        myIconLabel.setOpaque(false);
        myGamerPanel.add(myIconLabel);

        //"准备"字样设置
        myReadyLabel.setBounds(135, 53, 40, 40);
        myReadyLabel.setIcon(new ImageIcon("resource/img/ready.png"));
        myReadyLabel.setVisible(false);
        myGamerPanel.add(myReadyLabel);

        this.getContentPane().add(myGamerPanel);
    }

    /**
     * 初始化另一个玩家的信息(左上角)
     */
    private void initAnotherPlayerPanel() {
        anotherGamerPanel.setBounds(10, 78, 180, 290);
        anotherGamerPanel.setLayout(null);
        anotherGamerPanel.setOpaque(false);

        anotherNameLabel.setBounds(85, 110, 130, 45);
        anotherNameLabel.setOpaque(false);
        anotherGamerPanel.add(anotherNameLabel);

        anotherIconLabel.setBounds(62, 35, 70, 70);
        anotherIconLabel.setOpaque(false);
        anotherGamerPanel.add(anotherIconLabel);

        anotherReadyLabel.setBounds(135, 53, 40, 40);
        anotherReadyLabel.setIcon(new ImageIcon("resource/img/ready.png"));
        anotherReadyLabel.setVisible(false);
        anotherGamerPanel.add(anotherReadyLabel);

        this.getContentPane().add(anotherGamerPanel);
    }

    /**
     * 根据房间信息设置另一个人的信息界面.
     *
     * @param roomInfo
     */
    public void setAnotherPlayerPanel(RoomInfo roomInfo) {
        System.out.println(roomInfo);
        if (roomInfo.getRid() != rid) return;
        ChessUser chessUser;//另一个玩家
        boolean anotherReady;//储存另一个玩家是否准备
        if (isLeft) {//如果当前玩家在左侧,并且没准备,设置"准备"字样不可见
            if (roomInfo.isLeftReady() == false) {
                myReadyLabel.setVisible(false);
                readyPanelVisible = false;
            }
            //获取另一个玩家
            chessUser = roomInfo.getRightPlayer();
            anotherReady = roomInfo.isRightReady();
        } else {//如果当前玩家在右侧,并且没准备,设置"准备"字样不可见
            if (roomInfo.isRightReady()) {
                myReadyLabel.setVisible(false);
                readyPanelVisible = false;
            }
            chessUser = roomInfo.getLeftPlayer();
            anotherReady = roomInfo.isLeftReady();
        }
        if (chessUser != null) {//如果右边有玩家
            anotherReadyLabel.setVisible(anotherReady);
            anotherIconLabel.setIcon(new ImageIcon(chessUser.getFileName()));
            anotherNameLabel.setText(chessUser.getName());
        } else {
            if (gameStart == true) {//如果右侧玩家退出,或其他原因,导致游戏终止,需进行重置操作
                myReadyLabel.setIcon(new ImageIcon("resource/img/ready.png"));
                myReadyLabel.setVisible(false);
                gameStart = false;
                canBackGame = false;
                resetGame();
                repaint();
            }
            //不管游戏是否开始,右侧玩家为空都需要设置,所以不在上一个判断块里
            anotherReadyLabel.setIcon(new ImageIcon("resource/img/ready.png"));
            anotherReadyLabel.setVisible(false);
            anotherIconLabel.setIcon(null);
            anotherNameLabel.setText("");
        }
    }

    /**
     * 设置自另一玩家的"准备"显示
     *
     * @param roomInfo
     */
    public void setAnotherReadyLabel(RoomInfo roomInfo) {
        if (roomInfo.getRid() != rid) return;
        if (isLeft) {
            anotherReadyLabel.setVisible(roomInfo.isRightReady());
        } else {
            anotherReadyLabel.setVisible(roomInfo.isLeftReady());
        }
    }

    private void addAction() {
        readyButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                readyPanelVisible = !readyPanelVisible;
                myReadyLabel.setVisible(readyPanelVisible);
                ReadyMessage readyMessage = new ReadyMessage(rid, isLeft);
                ChessClient.getInstance().sendMessage(readyMessage);//发给服务器
            }
        });
        exitButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (gameStart == true) {
                    String[] options = {"确认退出(判定为输)", "手滑了"};
                    int res = JOptionPane.showOptionDialog(null, "是否确认退出", "退出本局",
                            JOptionPane.DEFAULT_OPTION, JOptionPane.YES_NO_OPTION,
                            null, options, options[0]);
                    if (res == 1) {
                        return;
                    }
                    GameOverMessage gameOverMessage = new GameOverMessage(getRid(), !isLeft);
                    ChessClient.getInstance().sendMessage(gameOverMessage);
                }
                OutRoomMessage outRoomMessage = new OutRoomMessage(rid, isLeft);
                ChessClient.getInstance().sendMessage(outRoomMessage);
                chessBoard.getChessAction().reset();
                toRoomList();
            }
        });
        regretButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (chessBoard.getChessCnt() == 0) {
                    System.out.println("无棋可悔");
                    return;
                }
                String[] options = {"发送悔棋请求", "取消悔棋"};
                int res = JOptionPane.showOptionDialog(null, "确认悔棋吗", "悔棋",
                        JOptionPane.DEFAULT_OPTION, JOptionPane.YES_NO_OPTION,
                        new ImageIcon("resource/img/back.png"), options, options[0]);
                if (res == 0) {
                    canPlayBeforeRegret = canPlay;
                    canPlay = false;
                    BackChessMessage backChessMessage = new BackChessMessage(rid, isLeft);
                    ChessClient.getInstance().sendMessage(backChessMessage);//发给服务器
                }
            }
        });
        giveInButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (gameStart == true) {
                    String[] options = {"确定认输", "继续本局"};
                    int res = JOptionPane.showOptionDialog(null, "是否确认认输", "向对方认输",
                            JOptionPane.DEFAULT_OPTION, JOptionPane.YES_NO_OPTION,
                            new ImageIcon("resource/img/touxiang.png"), options, options[0]);
                    if (res == 0) {
                        GameOverMessage gameOverMessage = new GameOverMessage(getRid(), !isLeft);
                        ChessClient.getInstance().sendMessage(gameOverMessage);
                    }
                }
            }
        });
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                OutRoomMessage outRoomMessage = new OutRoomMessage(rid, isLeft);
                ChessClient.getInstance().sendMessage(outRoomMessage);
                OffMessage offMessage = new OffMessage();
                ChessClient.getInstance().sendMessage(offMessage);
            }
        });
    }

    /**
     * 重置游戏内部属性
     */
    private void resetGame() {
        chessBoard.getChessAction().reset();//AI判断重置
        chessBoard.setChessCnt(0);//总下棋数重置
        //界面显示重置
        gameStart = false;
        canPlay = false;
        myReadyLabel.setIcon(new ImageIcon("resource/img/ready.png"));
        anotherReadyLabel.setIcon(new ImageIcon("resource/img/ready.png"));
        myReadyLabel.setVisible(false);
        anotherReadyLabel.setVisible(false);
        readyPanelVisible = false;
        repaint();
    }

    /**
     * 跳转至房间列表页面.
     */
    public void toRoomList() {
        roomList.setVisible(true);
        this.dispose();
    }

    /**
     * 游戏开始,将准备字样换为玩家的黑棋或白棋.
     */
    public void gameStart() {
        gameStart = true;
        if (isLeft) {
            myReadyLabel.setIcon(new ImageIcon("resource/img/black.png"));
            anotherReadyLabel.setIcon(new ImageIcon("resource/img/white.png"));
            canPlay = true;
        } else {
            myReadyLabel.setIcon(new ImageIcon("resource/img/white.png"));
            anotherReadyLabel.setIcon(new ImageIcon("resource/img/black.png"));
        }
    }

    /**
     * 收到请求悔棋报文后的弹出界面.
     */
    public void acceptRegretRequest() {
        boolean agreeRegret;
        String[] options = {"同意", "拒绝"};
        int res = JOptionPane.showOptionDialog(this, "是否同意", "对方请求悔棋",
                JOptionPane.DEFAULT_OPTION, JOptionPane.YES_NO_OPTION,
                null, options, options[0]);

        if (res == 0) {
            agreeRegret = true;
        } else {
            agreeRegret = false;
        }
        if (agreeRegret) {
            canPlay = false;
            canBackGame = false;
        }
        BackResultMessage message = new BackResultMessage(agreeRegret, rid, isLeft);
        ChessClient.getInstance().sendMessage(message);
    }

    /**
     * 平局显示的界面
     */
    public void gameDraw() {
        new Thread(new AudioPlayerThread("resource/audio/winner.wav")).start();
        JOptionPane.showMessageDialog(this,
                "平局", "势均力敌！", JOptionPane.ERROR_MESSAGE, new ImageIcon("resource/img/winner.png"));
        resetGame();
    }

    /**
     * 胜者显示的界面
     */
    public void win() {
        new Thread(new AudioPlayerThread("resource/audio/winner.wav")).start();
        JOptionPane.showMessageDialog(this,
                "大侠，在下甘拜下风！！", "你赢了！", JOptionPane.ERROR_MESSAGE, new ImageIcon("resource/imag/winner.png"));
        resetGame();
    }

    /**
     * 败者显示的界面
     */
    public void defeat() {
        new Thread(new AudioPlayerThread("resource/audio/loser.wav")).start();
        JOptionPane.showMessageDialog(this,
                "胜败乃兵家常事，壮士请重新来过", "你输了！", JOptionPane.ERROR_MESSAGE, new ImageIcon("resource/imag/loser.png"));
        resetGame();
    }

    /**
     * 收到对方同意悔棋报文后弹出.
     */
    public void BackSucceed() {
        canBackGame = false;
        canPlay = true;
        chessBoard.backForOnline();
        JOptionPane.showMessageDialog(this,
                "悔棋成功", "对方同意了你的请求", JOptionPane.ERROR_MESSAGE);
    }

    /**
     * 收到对方不同意悔棋报文后弹出.
     */
    public void BackFail() {
        if (canPlayBeforeRegret) {//记录悔棋之前能不能下棋
            canPlay = true;
        }
        JOptionPane.showMessageDialog(this,
                "悔棋失败", "对方拒绝了你的请求", JOptionPane.ERROR_MESSAGE);
    }
}
